/*
 * Copyright (c) 2017 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef __HTTP_H__
#define __HTTP_H__

#include <net/net_context.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief HTTP client and server library
 * @defgroup http HTTP Library
 * @{
 */

#if defined(CONFIG_HTTPS)
#if defined(CONFIG_MBEDTLS)
#if !defined(CONFIG_MBEDTLS_CFG_FILE)
#include "mbedtls/config.h"
#else
#include CONFIG_MBEDTLS_CFG_FILE
#endif /* CONFIG_MBEDTLS_CFG_FILE */

#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdlib.h>
#define mbedtls_time_t       time_t
#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS
#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE
#endif /* MBEDTLS_PLATFORM_C */

#include <mbedtls/ssl_cookie.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/net_sockets.h>
#include <mbedtls/x509.h>
#include <mbedtls/x509_crt.h>
#include <mbedtls/ssl.h>
#include <mbedtls/error.h>
#include <mbedtls/debug.h>
#endif /* CONFIG_MBEDTLS */
#endif /* CONFIG_HTTPS */

#define HTTP_CRLF "\r\n"

#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
void http_heap_init(void);
#else
#define http_heap_init()
#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */

typedef int (*http_send_data_t)(struct net_pkt *pkt,
				net_context_send_cb_t cb,
				s32_t timeout,
				void *token,
				void *user_data);

#if defined(CONFIG_HTTPS)
/* Internal information for managing HTTPS data */
struct https_context {
	struct net_pkt *rx_pkt;
	struct net_buf *frag;
	struct k_sem tx_sem;
	struct k_fifo rx_fifo;
	struct k_fifo tx_fifo;
	int remaining;
};

/**
 * @typedef https_entropy_src_cb_t
 * @brief Callback used when the API user needs to setup the entropy source.
 * @detail This is the same as mbedtls_entropy_f_source_ptr callback.
 *
 * @param data Callback-specific data pointer
 * @param output Data to fill
 * @param len Maximum size to provide
 * @param olen The actual amount of bytes put into the buffer (Can be 0)
 */
typedef int (*https_entropy_src_cb_t)(void *data, unsigned char *output,
				      size_t len, size_t *olen);
#endif /* CONFIG_HTTPS */

#if defined(CONFIG_HTTP_CLIENT)

#include <net/http_parser.h>
#include <net/net_context.h>

/* Is there more data to come */
enum http_final_call {
	HTTP_DATA_MORE = 0,
	HTTP_DATA_FINAL = 1,
};

#ifndef HTTP_PROTOCOL
#define HTTP_PROTOCOL	   "HTTP/1.1"
#endif

/* Some generic configuration options, these can be overriden if needed. */
#ifndef HTTP_STATUS_STR_SIZE
#define HTTP_STATUS_STR_SIZE	32
#endif

/* It seems enough to hold 'Content-Length' and its value */
#define HTTP_CONTENT_LEN_SIZE	48

/* Default HTTP Header Field values for HTTP Requests if using the
 * HTTP_HEADER_FIELDS define.
 */
#ifndef HTTP_ACCEPT
#define HTTP_ACCEPT		"text/plain"
#endif

#ifndef HTTP_ACCEPT_ENC
#define HTTP_ACCEPT_ENC		"identity"
#endif

#ifndef HTTP_ACCEPT_LANG
#define HTTP_ACCEPT_LANG	"en-US"
#endif

#ifndef HTTP_CONNECTION
#define HTTP_CONNECTION		"Close"
#endif

#ifndef HTTP_USER_AGENT
#define HTTP_USER_AGENT	"Zephyr-HTTP-Client/1.8"
#endif

/* This can be used in http_client_send_get_req() when supplying
 * extra_header_fields parameter.
 */
#ifndef HTTP_HEADER_FIELDS
#define HTTP_HEADER_FIELDS				     \
	"Accept: " HTTP_ACCEPT HTTP_CRLF		     \
	"Accept-Encoding: " HTTP_ACCEPT_ENC HTTP_CRLF	     \
	"Accept-Language: " HTTP_ACCEPT_LANG HTTP_CRLF	     \
	"User-Agent: " HTTP_USER_AGENT HTTP_CRLF	     \
	"Connection: " HTTP_CONNECTION HTTP_CRLF
#endif

struct http_client_ctx;

/**
 * @typedef http_receive_cb_t
 * @brief Callback used when TCP data has been received from peer.
 *
 * @param ctx HTTP context.
 * @param pkt Network packet.
 */
typedef void (*http_receive_cb_t)(struct http_client_ctx *ctx,
				  struct net_pkt *pkt);

/**
 * @typedef http_response_cb_t
 * @brief Callback used when a response has been received from peer.
 *
 * @param ctx HTTP context.
 * @param data Received data buffer
 * @param buflen Data buffer len (as specified by user)
 * @param datalen Received data len, if this is larger than buflen,
 * then some data was skipped.
 * @param final_data Does this data buffer contain all the data or
 * is there still more data to come.
 * @param user_data A valid pointer on some user data or NULL
 */
typedef void (*http_response_cb_t)(struct http_client_ctx *ctx,
				   u8_t *data, size_t buflen,
				   size_t datalen,
				   enum http_final_call final_data,
				   void *user_data);

#if defined(CONFIG_HTTPS)
/**
 * @typedef https_ca_cert_cb_t
 * @brief Callback used when the API user needs to setup the
 * HTTPS certs.
 *
 * @param ctx HTTPS client context.
 * @param ca_cert MBEDTLS certificate. This is of type mbedtls_x509_crt
 * if MBEDTLS_X509_CRT_PARSE_C is defined.
 *
 * @return 0 if ok, <0 if there is an error
 */
typedef int (*https_ca_cert_cb_t)(struct http_client_ctx *ctx,
				  void *ca_cert);
#endif /* CONFIG_HTTPS */

/**
 * HTTP client context information. This contains all the data that is
 * needed when doing HTTP requests.
 */
struct http_client_ctx {
	struct http_parser parser;
	struct http_parser_settings settings;

	/** Server name */
	const char *server;

#if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL)
	/** Network packet (net_pkt) memory pool for network contexts attached
	 * to this http_client context.
	 */
	net_pkt_get_slab_func_t tx_slab;

	/** Network data net_buf pool for network contexts attached to this
	 * http_client context.
	 */
	net_pkt_get_pool_func_t data_pool;
#endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */

	/** Is this instance HTTPS or not.
	 */
	bool is_https;

#if defined(CONFIG_DNS_RESOLVER)
	/** Remember the DNS query id so that it can be cancelled
	 * if the HTTP context is released and the query is active
	 * at that time.
	 */
	u16_t dns_id;
#endif

	struct {
		/** Local socket address */
		struct sockaddr local;

		/** Remote (server) socket address */
		struct sockaddr remote;

		/** IP stack network context */
		struct net_context *ctx;

		/** Network timeout */
		s32_t timeout;

		/** User can define this callback if it wants to have
		 * special handling of the received raw data. Note that this
		 * callback is not called for HTTPS data.
		 */
		http_receive_cb_t receive_cb;

		/** Internal function that is called when HTTP data is
		 * received from network.
		 */
		net_context_recv_cb_t recv_cb;

		/** Internal function that is called when HTTP data is sent to
		 * network.
		 */
		http_send_data_t send_data;
	} tcp;

	/** HTTP request information */
	struct {
		/**
		 * Semaphore to signal HTTP request completion
		 */
		struct k_sem wait;

		/** Hostname to be used in the request */
		const char *host;

		/** User provided data */
		void *user_data;

		/** What method we used here (GET, POST, HEAD etc.)
		 */
		enum http_method method;
	} req;

	/** HTTP response information */
	struct {
		/** User provided HTTP response callback which is called
		 * when a response is received to a sent HTTP request.
		 */
		http_response_cb_t cb;

		/** Where the response is stored, this is to be provided
		 * by the user.
		 */
		u8_t *response_buf;

		/** Where the body starts.
		 */
		u8_t *body_start;

		/** Response buffer maximum length */
		size_t response_buf_len;

		/** Length of the data in the result buf. If the value is
		 * larger than response_buf_len, then it means that the data
		 * is truncated and could not be fully copied into
		 * response_buf. This can only happen if the user did not
		 * set the response callback. If the callback is set, then
		 * the HTTP client API will call response callback many times
		 * so that all the data is delivered to the user.
		 */
		size_t data_len;

		/** HTTP Content-Length field value */
		size_t content_length;

		/** Content length parsed. This should be the same as the
		 * content_length field if parsing was ok.
		 */
		size_t processed;

		/* https://tools.ietf.org/html/rfc7230#section-3.1.2
		 * The status-code element is a 3-digit integer code
		 *
		 * The reason-phrase element exists for the sole purpose of
		 * providing a textual description associated with the
		 * numeric status code. A client SHOULD ignore the
		 * reason-phrase content.
		 */
		char http_status[HTTP_STATUS_STR_SIZE];

		u8_t cl_present:1;
		u8_t body_found:1;
		u8_t message_complete:1;
	} rsp;

#if defined(CONFIG_HTTPS)
	struct {
		/** HTTPS stack for mbedtls library. */
		k_thread_stack_t stack;

		/** HTTPS stack size. */
		int stack_size;

		/** HTTPS thread id */
		k_tid_t tid;

		/** HTTPS thread */
		struct k_thread thread;

		/** Memory pool for RX data */
		struct k_mem_pool *pool;

		/** Hostname to be used in the certificate verification */
		const char *cert_host;

		/** mbedtls related configuration. */
		struct {
			struct https_context ssl_ctx;
			https_ca_cert_cb_t cert_cb;
			https_entropy_src_cb_t entropy_src_cb;
			mbedtls_entropy_context entropy;
			mbedtls_ctr_drbg_context ctr_drbg;
			mbedtls_ssl_context ssl;
			mbedtls_ssl_config conf;
			mbedtls_x509_crt ca_cert;
			u8_t *personalization_data;
			size_t personalization_data_len;
		} mbedtls;
	} https;
#endif /* CONFIG_HTTPS */
};

/**
 * HTTP client request. This contains all the data that is needed when doing
 * a HTTP request.
 */
struct http_client_request {
	/** The HTTP method: GET, HEAD, OPTIONS, POST, ... */
	enum http_method method;

	/** The URL for this request, for example: /index.html */
	const char *url;

	/** The HTTP protocol: HTTP/1.1 */
	const char *protocol;

	/** The HTTP header fields (application specific)
	 * The Content-Type may be specified here or in the next field.
	 * Depending on your application, the Content-Type may vary, however
	 * some header fields may remain constant through the application's
	 * life cycle.
	 */
	const char *header_fields;

	/** The value of the Content-Type header field, may be NULL */
	const char *content_type_value;

	/** Hostname to be used in the request */
	const char *host;

	/** Payload, may be NULL */
	const char *payload;

	/** Payload size, may be 0 */
	u16_t payload_size;
};

/**
 * @brief Generic function to send a HTTP request to the network. Normally
 * applications would not need to use this function.
 *
 * @param ctx HTTP client context.
 * @param req HTTP request to perform.
 * @param timeout Timeout when doing net_buf allocations.
 *
 * @return Return 0 if ok, and <0 if error.
 */
int http_request(struct http_client_ctx *ctx,
		 struct http_client_request *req,
		 s32_t timeout);

/**
 * @brief Send a HTTP request to peer.
 *
 * @param http_ctx HTTP context.
 * @param req HTTP request to perform.
 * @param cb Callback to call when the response has been received from peer.
 * @param response_buf Caller-supplied buffer where the HTTP response will be
 * stored
 * @param response_buf_len Length of the caller-supplied buffer.
 * @param user_data A valid pointer on some user data or NULL
 * @param timeout Amount of time to wait for a reply. If the timeout is 0,
 * then we return immediately and the callback (if set) will be called later.
 *
 * @return Return 0 if ok, and <0 if error.
 */
int http_client_send_req(struct http_client_ctx *http_ctx,
			 struct http_client_request *req,
			 http_response_cb_t cb,
			 u8_t *response_buf,
			 size_t response_buf_len,
			 void *user_data,
			 s32_t timeout);

/**
 * @brief Send a HTTP GET request to peer.
 *
 * @param http_ctx HTTP context.
 * @param url URL to use.
 * @param host Host field in HTTP header. If set to NULL, then server
 * name is used.
 * @param extra_header_fields Any extra header fields that caller wants
 * to add. This can be set to NULL. The format is "name: value\r\n"
 * Example: "Accept: text/plain\r\nConnection: Close\r\n"
 * @param cb Callback to call when the response has been received from peer.
 * @param response_buf Caller-supplied buffer where the HTTP request will be
 * stored
 * @param response_buf_len Length of the caller-supplied buffer.
 * @param user_data A valid pointer on some user data or NULL
 * @param timeout Amount of time to wait for a reply. If the timeout is 0,
 * then we return immediately and the callback (if set) will be called later.
 *
 * @return Return 0 if ok, and <0 if error.
 */
static inline int http_client_send_get_req(struct http_client_ctx *http_ctx,
					   const char *url,
					   const char *host,
					   const char *extra_header_fields,
					   http_response_cb_t cb,
					   u8_t *response_buf,
					   size_t response_buf_len,
					   void *user_data,
					   s32_t timeout)
{
	struct http_client_request req = {
				.method = HTTP_GET,
				.url = url,
				.host = host,
				.protocol = " " HTTP_PROTOCOL HTTP_CRLF,
				.header_fields = extra_header_fields,
	};

	return http_client_send_req(http_ctx, &req, cb, response_buf,
				    response_buf_len, user_data, timeout);
}

/**
 * @brief Send a HTTP POST request to peer.
 *
 * @param http_ctx HTTP context.
 * @param url URL to use.
 * @param host Host field in HTTP header. If set to NULL, then server
 * name is used.
 * @param extra_header_fields Any extra header fields that caller wants
 * to add. This can be set to NULL. The format is "name: value\r\n"
 * Example: "Accept: text/plain\r\nConnection: Close\r\n"
 * @param content_type Content type of the data.
 * @param payload Payload data.
 * @param cb Callback to call when the response has been received from peer.
 * @param response_buf Caller-supplied buffer where the HTTP response will be
 * stored
 * @param response_buf_len Length of the caller-supplied buffer.
 * @param user_data A valid pointer on some user data or NULL
 * @param timeout Amount of time to wait for a reply. If the timeout is 0,
 * then we return immediately and the callback (if set) will be called later.
 *
 * @return Return 0 if ok, and <0 if error.
 */
static inline int http_client_send_post_req(struct http_client_ctx *http_ctx,
					    const char *url,
					    const char *host,
					    const char *extra_header_fields,
					    const char *content_type,
					    const char *payload,
					    http_response_cb_t cb,
					    u8_t *response_buf,
					    size_t response_buf_len,
					    void *user_data,
					    s32_t timeout)
{
	struct http_client_request req = {
				.method = HTTP_POST,
				.url = url,
				.host = host,
				.protocol = " " HTTP_PROTOCOL HTTP_CRLF,
				.header_fields = extra_header_fields,
				.content_type_value = content_type,
				.payload = payload,
	};

	return http_client_send_req(http_ctx, &req, cb, response_buf,
				    response_buf_len, user_data, timeout);
}

/**
 * @brief Initialize user-supplied HTTP context.
 *
 * @detail Caller can set the various fields in http_ctx after this call
 * if needed.
 *
 * @param http_ctx HTTP context.
 * @param server HTTP server address or host name. If host name is given,
 * then DNS resolver support (CONFIG_DNS_RESOLVER) must be enabled. If caller
 * sets the server parameter as NULL, then no attempt is done to figure out
 * the remote address and caller must set the address in http_ctx.tcp.remote
 * itself.
 * @param server_port HTTP server TCP port.
 *
 * @return Return 0 if ok, <0 if error.
 */
int http_client_init(struct http_client_ctx *http_ctx,
		     const char *server, u16_t server_port);

#if defined(CONFIG_HTTPS)
/**
 * @brief Initialize user-supplied HTTP context when using HTTPS.
 *
 * @detail Caller can set the various fields in http_ctx after this call
 * if needed.
 *
 * @param http_ctx HTTPS context.
 * @param server HTTPS server address or host name. If host name is given,
 * then DNS resolver support (CONFIG_DNS_RESOLVER) must be enabled. If caller
 * sets the server parameter as NULL, then no attempt is done to figure out
 * the remote address and caller must set the address in http_ctx.tcp.remote
 * itself.
 * @param server_port HTTPS server TCP port.
 * @param personalization_data Personalization data (Device specific
 * identifiers) for random number generator. (Can be NULL).
 * @param personalization_data_len Length of the personalization data.
 * @param cert_cb User-supplied callback that setups the certificates.
 * @param cert_host Hostname that is used to verify the server certificate.
 * This value is used when HTTP client API calls mbedtls_ssl_set_hostname()
 * which sets the hostname to check against the received server certificate.
 * See https://tls.mbed.org/kb/how-to/use-sni for more details.
 * This can be left NULL in which case mbedtls will silently skip certificate
 * verification entirely. This option is only used if MBEDTLS_X509_CRT_PARSE_C
 * is enabled in mbedtls config file.
 * @param entropy_src_cb User-supplied callback that setup the entropy. This
 * can be set to NULL, in which case default entropy source is used.
 * @param pool Memory pool for RX data reads.
 * @param https_stack HTTPS thread stack.
 * @param https_stack_len HTTP thread stack size.
 *
 * @return Return 0 if ok, <0 if error.
 */
int https_client_init(struct http_client_ctx *http_ctx,
		      const char *server, u16_t server_port,
		      u8_t *personalization_data,
		      size_t personalization_data_len,
		      https_ca_cert_cb_t cert_cb,
		      const char *cert_host,
		      https_entropy_src_cb_t entropy_src_cb,
		      struct k_mem_pool *pool,
		      k_thread_stack_t https_stack,
		      size_t https_stack_size);
#endif /* CONFIG_HTTPS */

/**
 * @brief Release all the resources allocated for HTTP context.
 *
 * @param http_ctx HTTP context.
 */
void http_client_release(struct http_client_ctx *http_ctx);

#if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL)
/**
 * @brief Configure the net_pkt pool for this context.
 *
 * @details Use of this function is optional and if the pools are not set,
 * then the default TX and DATA pools are used. This needs to be called before
 * http init function, as that will setup net_context which needs the net_pkt
 * pool information.
 *
 * @param ctx HTTP client context
 * @param tx_slab Function which is used when allocating TX network packet.
 * This can be NULL in which case default TX memory pool is used.
 * @param data_pool Function which is used when allocating data network buffer.
 * This can be NULL in which case default DATA net_buf pool is used.
 */
int http_client_set_net_pkt_pool(struct http_client_ctx *ctx,
				 net_pkt_get_slab_func_t tx_slab,
				 net_pkt_get_pool_func_t data_pool);
#else
#define http_client_set_net_pkt_pool(...)
#endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */
#endif /* CONFIG_HTTP_CLIENT */

#if defined(CONFIG_HTTP_SERVER)

#include <net/net_context.h>
#include <net/http_parser.h>

struct http_server_ctx;

enum http_url_flags {
	HTTP_URL_STANDARD = 0,
};

/* HTTP header fields struct */
struct http_field_value {
	/** Field name, this variable will point to the beginning of the string
	 *  containing the HTTP field name
	 */
	const char *key;

	/** Value, this variable will point to the beginning of the string
	 *  containing the field value
	 */
	const char *value;

	/** Length of the field name */
	u16_t key_len;

	/** Length of the field value */
	u16_t value_len;
};

typedef int (*http_url_cb_t)(struct http_server_ctx *ctx);

/* HTTP root URL struct, used for pattern matching */
struct http_root_url {
	/** URL */
	const char *root;

	/** Callback that is called when this URL is received */
	http_url_cb_t write_cb;

	/** Length of the URL */
	u16_t root_len;

	/** Flags for this URL (values are from enum http_url_flags) */
	u8_t flags;

	/** Is this URL resource used or not */
	u8_t is_used;
};

/* Collection of URLs that this server will handle */
struct http_server_urls {
	/* First item is the default handler and it is always there.
	 */
	struct http_root_url default_url;
	struct http_root_url urls[CONFIG_HTTP_SERVER_NUM_URLS];
};

#if defined(CONFIG_HTTPS)
/**
 * @typedef https_server_cert_cb_t
 * @brief Callback used when the API user needs to setup the
 * HTTPS certs.
 *
 * @param ctx HTTPS server context.
 * @param cert MBEDTLS certificate
 * @param pkey MBEDTLS private key
 *
 * @return 0 if ok, <0 if there is an error
 */
typedef int (*https_server_cert_cb_t)(struct http_server_ctx *ctx,
				      mbedtls_x509_crt *cert,
				      mbedtls_pk_context *pkey);
#endif /* CONFIG_HTTPS */

/* The HTTP server context struct */
struct http_server_ctx {
	/** Collection of URLs that this server context will handle */
	struct http_server_urls *urls;

#if defined(CONFIG_NET_IPV4)
	/** IPv4 stack network context for listening */
	struct net_context *net_ipv4_ctx;
#endif
#if defined(CONFIG_NET_IPV6)
	/** IPv6 stack network context for listening */
	struct net_context *net_ipv6_ctx;
#endif

	/** Function that is called when data is received from network. */
	net_context_recv_cb_t recv_cb;

	/** Function that is called when data is sent to network. */
	http_send_data_t send_data;

#if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL)
	/** Network packet (net_pkt) memory pool for network contexts attached
	 * to this http server context.
	 */
	net_pkt_get_slab_func_t tx_slab;

	/** Network data net_buf pool for network contexts attached to this
	 * http server context.
	 */
	net_pkt_get_pool_func_t data_pool;
#endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */

#if defined(CONFIG_NET_DEBUG_HTTP_CONN)
	sys_snode_t node;
#endif

	/** Network timeout */
	s32_t timeout;

	/** Running status of the server. If true, then the server is enabled.
	 * If false then it is disabled and will not serve clients.
	 * The server is disabled by default after initialization and will need
	 * to be enabled manually.
	 */
	bool enabled;

	/** Is this instance HTTPS or not.
	 */
	bool is_https;

	struct {
		/** From which net_context the request came from */
		struct net_context *net_ctx;

		/** HTTP request timer. After sending a response to the
		 * client, it is possible to wait for any request back via
		 * the same socket. If no response is received, then this
		 * timeout is activated and connection is tore down.
		 */
		struct k_delayed_work timer;

		/** HTTP parser */
		struct http_parser parser;

		/** HTTP parser settings */
		struct http_parser_settings settings;

		/** Collection of header fields */
		struct http_field_value
				field_values[CONFIG_HTTP_HEADER_FIELD_ITEMS];

		/** HTTP Request URL */
		const char *url;

		/** Where the request is stored, this is to be provided
		 * by the user.
		 */
		u8_t *request_buf;

		/** Request buffer maximum length */
		size_t request_buf_len;

		/** Length of the data in the request buf. */
		size_t data_len;

		/** Number of header field elements */
		u16_t field_values_ctr;

		/** URL's length */
		u16_t url_len;
	} req;

#if defined(CONFIG_HTTPS)
	struct {
		/** HTTPS stack for mbedtls library. */
		k_thread_stack_t stack;

		/** HTTPS stack size. */
		int stack_size;

		/** HTTPS thread id */
		k_tid_t tid;

		/** HTTPS thread */
		struct k_thread thread;

		/** Memory pool for RX data */
		struct k_mem_pool *pool;

		/** mbedtls related configuration. */
		struct {
			struct https_context ssl_ctx;
			https_server_cert_cb_t cert_cb;
			https_entropy_src_cb_t entropy_src_cb;
			mbedtls_entropy_context entropy;
			mbedtls_ctr_drbg_context ctr_drbg;
			mbedtls_ssl_context ssl;
			mbedtls_ssl_config conf;
			mbedtls_x509_crt srvcert;
			mbedtls_pk_context pkey;
			u8_t *personalization_data;
			size_t personalization_data_len;
		} mbedtls;
	} https;
#endif /* CONFIG_HTTPS */
};

#if defined(CONFIG_NET_DEBUG_HTTP_CONN)
typedef void (*http_server_cb_t)(struct http_server_ctx *entry,
				 void *user_data);

void http_server_conn_foreach(http_server_cb_t cb, void *user_data);
void http_server_conn_monitor(http_server_cb_t cb, void *user_data);
#else
#define http_server_conn_foreach(...)
#define http_server_conn_monitor(...)
#endif /* CONFIG_NET_DEBUG_HTTP_CONN */

/**
 * @brief Initialize user-supplied HTTP context.
 *
 * @detail Caller can set the various callback fields in http_ctx and
 * http_ctx.req.parser after this call if needed.
 *
 * @param http_ctx HTTP context.
 * @param urls Array of URLs that the server instance will serve. If the
 * server receives a HTTP request into one of the URLs, it will call user
 * supplied callback. If no such URL is registered, a default handler will
 * be called (if set by the user). If no data handler is found, the request
 * is dropped.
 * @param server_addr Socket address of the local network interface and TCP
 * port where the data is being waited. If the socket family is set to
 * AF_UNSPEC, then both IPv4 and IPv6 is started to be listened. If the
 * address is set to be INADDR_ANY (for IPv4) or unspecified address (all bits
 * zeros for IPv6), then the HTTP server will select proper IP address to bind
 * to. If caller has not specified HTTP listening port, then port 80 is being
 * listened. The parameter can be left NULL in which case a listener to port 80
 * using IPv4 and IPv6 is created. Note that if IPv4 or IPv6 is disabled, then
 * the corresponding disabled service listener is not created.
 * @param request_buf Caller-supplied buffer where the HTTP request will be
 * stored
 * @param request_buf_len Length of the caller-supplied buffer.
 * @param server_banner Print information about started service. This is only
 * printed if HTTP debugging is activated. The parameter can be set to NULL if
 * no extra prints are needed.
 *
 * @return Return 0 if ok, <0 if error.
 */
int http_server_init(struct http_server_ctx *http_ctx,
		     struct http_server_urls *urls,
		     struct sockaddr *server_addr,
		     u8_t *request_buf,
		     size_t request_buf_len,
		     const char *server_banner);

#if defined(CONFIG_HTTPS)
/**
 * @brief Initialize user-supplied HTTP context. This function must be
 * used if HTTPS server is created.
 *
 * @detail Caller can set the various callback fields in http_ctx and
 * http_ctx.req.parser after this call if needed.
 *
 * @param http_ctx HTTP context.
 * @param urls Array of URLs that the server instance will serve. If the
 * server receives a HTTP request into one of the URLs, it will call user
 * supplied callback. If no such URL is registered, a default handler will
 * be called (if set by the user). If no data handler is found, the request
 * is dropped.
 * @param server_addr Socket address of the local network interface and TCP
 * port where the data is being waited. If the socket family is set to
 * AF_UNSPEC, then both IPv4 and IPv6 is started to be listened. If the
 * address is set to be INADDR_ANY (for IPv4) or unspecified address (all bits
 * zeros for IPv6), then the HTTP server will select proper IP address to bind
 * to. If caller has not specified HTTP listening port, then port 80 is being
 * listened. The parameter can be left NULL in which case a listener to port 80
 * using IPv4 and IPv6 is created. Note that if IPv4 or IPv6 is disabled, then
 * the corresponding disabled service listener is not created.
 * @param request_buf Caller-supplied buffer where the HTTP request will be
 * stored
 * @param request_buf_len Length of the caller-supplied buffer.
 * @param server_banner Print information about started service. This is only
 * printed if HTTP debugging is activated. The parameter can be set to NULL if
 * no extra prints are needed.
 * @param personalization_data Personalization data (Device specific
 * identifiers) for random number generator. (Can be NULL).
 * @param personalization_data_len Length of the personalization data.
 * @param cert_cb User-supplied callback that setups the certificates.
 * @param entropy_src_cb User-supplied callback that setup the entropy. This
 * can be set to NULL, in which case default entropy source is used.
 * @param pool Memory pool for RX data reads.
 * @param https_stack HTTPS thread stack.
 * @param https_stack_len HTTP thread stack size.
 *
 * @return Return 0 if ok, <0 if error.
 */
int https_server_init(struct http_server_ctx *http_ctx,
		      struct http_server_urls *urls,
		      struct sockaddr *server_addr,
		      u8_t *request_buf,
		      size_t request_buf_len,
		      const char *server_banner,
		      u8_t *personalization_data,
		      size_t personalization_data_len,
		      https_server_cert_cb_t cert_cb,
		      https_entropy_src_cb_t entropy_src_cb,
		      struct k_mem_pool *pool,
		      k_thread_stack_t https_stack,
		      size_t https_stack_len);
#endif /* CONFIG_HTTPS */

/**
 * @brief Release all the resources allocated for HTTP context.
 *
 * @param http_ctx HTTP context.
 */
void http_server_release(struct http_server_ctx *http_ctx);

/**
 * @brief Enable HTTP server that is related to this context.
 *
 * @detail The HTTP server will start to serve request after this.
 *
 * @param http_ctx HTTP context.
 *
 * @return Previous status of the server.
 */
bool http_server_enable(struct http_server_ctx *http_ctx);

/**
 * @brief Disable HTTP server that is related to this context.
 *
 * @detail The HTTP server will stop to serve request after this.
 *
 * @param http_ctx HTTP context.
 *
 * @return Previous status of the server.
 */
bool http_server_disable(struct http_server_ctx *http_ctx);

/**
 * @brief Helper function that can be used to fill the server (local) sockaddr
 * struct.
 *
 * @param addr Sockaddr struct to be filled.
 * @param myaddr Address that the local IP address. If left NULL, then the
 * proper system address is used.
 * @param port TCP port to use.
 *
 * @return 0 if ok, <0 if error.
 */
int http_server_set_local_addr(struct sockaddr *addr, const char *myaddr,
			       u16_t port);

/**
 * @brief Add a handler for a given URL.
 *
 * @detail Register a handler which is called if the server receives a
 * request to a given URL.
 *
 * @param urls URL struct that will contain all the URLs the user wants to
 * register.
 * @param url URL string.
 * @param flags Flags for the URL.
 * @param write_cb Callback that is called when URL is requested.
 *
 * @return NULL if the URL is already registered, pointer to  URL if
 * registering was ok.
 */
struct http_root_url *http_server_add_url(struct http_server_urls *urls,
					  const char *url, u8_t flags,
					  http_url_cb_t write_cb);

/**
 * @brief Delete the handler for a given URL.
 *
 * @detail Unregister the previously registered URL handler.
 *
 * @param urls URL struct that will contain all the URLs the user has
 * registered.
 * @param url URL string.
 *
 * @return 0 if ok, <0 if error.
 */
int http_server_del_url(struct http_server_urls *urls, const char *url);

/**
 * @brief Add default URL handler.
 *
 * @detail If no URL handler is found, then call this handler. There can
 * be only one default handler in the URL struct.
 *
 * @param urls URL struct that will contain all the URLs the user has
 * registered.
 * @param write_cb Callback that is called when non-registered URL is
 * requested.
 *
 * @return NULL if default URL is already registered, pointer to default
 * URL if registering was ok.
 */
struct http_root_url *http_server_add_default(struct http_server_urls *urls,
					      http_url_cb_t write_cb);

/**
 * @brief Delete the default URL handler.
 *
 * @detail Unregister the previously registered default URL handler.
 *
 * @param urls URL struct that will contain all the URLs the user has
 * registered.
 *
 * @return 0 if ok, <0 if error.
 */
int http_server_del_default(struct http_server_urls *urls);

/**
 * @brief Send HTTP response to client.
 *
 * @detail After sending a response, an optional timeout is started
 * which will wait for any new requests from the peer.
 *
 * @param ctx HTTP context.
 * @param http_header HTTP headers to send.
 * @param html_payload HTML payload to send.
 * @param timeout Timeout to wait until the connection is shutdown.
 *
 * @return 0 if ok, <0 if error.
 */
int http_response_wait(struct http_server_ctx *ctx, const char *http_header,
		       const char *html_payload, s32_t timeout);

/**
 * @brief Send HTTP response to client.
 *
 * @detail The connection to peer is torn down right after the response
 * is sent.
 *
 * @param ctx HTTP context.
 * @param http_header HTTP headers to send.
 * @param html_payload HTML payload to send.
 *
 * @return 0 if ok, <0 if error.
 */
int http_response(struct http_server_ctx *ctx, const char *http_header,
		  const char *html_payload);

/**
 * @brief Send HTTP 400 response to client.
 *
 * @detail HTTP 400 error code indicates a Bad Request
 *
 * @param ctx HTTP context.
 * @param html_payload HTML payload to send.
 *
 * @return 0 if ok, <0 if error.
 */
int http_response_400(struct http_server_ctx *ctx, const char *html_payload);

/**
 * @brief Send HTTP 403 response to client.
 *
 * @detail HTTP 403 error code indicates a Forbidden Request
 *
 * @param ctx HTTP context.
 * @param html_payload HTML payload to send.
 *
 * @return 0 if ok, <0 if error.
 */
int http_response_403(struct http_server_ctx *ctx, const char *html_payload);

/**
 * @brief Send HTTP 404 response to client.
 *
 * @detail HTTP 404 error code indicates a Not Found resource.
 *
 * @param ctx HTTP context.
 * @param html_payload HTML payload to send.
 *
 * @return 0 if ok, <0 if error.
 */
int http_response_404(struct http_server_ctx *ctx, const char *html_payload);

/**
 * @brief Send some data to the client.
 *
 * @detail Send a piece of data to the client. If html_payload is NULL, then
 * we close the connection.
 *
 * @param ctx HTTP context.
 * @param http_header HTTP header to be sent. Can be NULL.
 * @param html_payload HTML payload to send.
 * @param timeout Timeout to wait until the connection is teared down.
 *
 * @return 0 if ok, <0 if error.
 */
int http_response_send_data(struct http_server_ctx *ctx,
			    const char *http_header,
			    const char *html_payload,
			    s32_t timeout);

#if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL)
/**
 * @brief Configure the net_pkt pool for this context.
 *
 * @details Use of this function is optional and if the pools are not set,
 * then the default TX and DATA pools are used. This needs to be called before
 * http init function, as that will setup net_context which needs the net_pkt
 * pool information.
 *
 * @param ctx HTTP server context
 * @param tx_slab Function which is used when allocating TX network packet.
 * This can be NULL in which case default TX memory pool is used.
 * @param data_pool Function which is used when allocating data network buffer.
 * This can be NULL in which case default DATA net_buf pool is used.
 */
int http_server_set_net_pkt_pool(struct http_server_ctx *ctx,
				 net_pkt_get_slab_func_t tx_slab,
				 net_pkt_get_pool_func_t data_pool);
#else
#define http_server_set_net_pkt_pool(...)
#endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */

#endif /* CONFIG_HTTP_SERVER */

#ifdef __cplusplus
}
#endif

/**
 * @}
 */

#endif /* __HTTP_H__ */
